/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.hos_ahmedadeltito.photoeditorsdk;

import ohos.agp.components.Component;
import ohos.agp.utils.Point;
import ohos.multimodalinput.event.MmiPoint;
import ohos.multimodalinput.event.TouchEvent;

//多点触控
public class ScaleGestureDetector {
    private static final String TAG = "ScaleGestureDetector";

    interface OnScaleGestureListener {

        boolean onScale(Component view, ScaleGestureDetector detector);


        boolean onScaleBegin(Component view, ScaleGestureDetector detector);

        void onScaleEnd(Component view, ScaleGestureDetector detector);
    }

    static class SimpleOnScaleGestureListener implements OnScaleGestureListener {

        public boolean onScale(Component view, ScaleGestureDetector detector) {
            return false;
        }

        public boolean onScaleBegin(Component view, ScaleGestureDetector detector) {
            return true;
        }

        public void onScaleEnd(Component view, ScaleGestureDetector detector) {
            // Intentionally empty
        }
    }

    private static final float PRESSURE_THRESHOLD = 0.67f;

    private final OnScaleGestureListener mListener;
    private boolean mGestureInProgress;

    private TouchEvent mPrevEvent;
    private TouchEvent mCurrEvent;

    private Vector2D mCurrSpanVector;
    private float mFocusX;
    private float mFocusY;
    private float mPrevFingerDiffX;
    private float mPrevFingerDiffY;
    private float mCurrFingerDiffX;
    private float mCurrFingerDiffY;
    private float mCurrLen;
    private float mPrevLen;
    private float mScaleFactor;
    private float mCurrPressure;
    private float mPrevPressure;
    private long mTimeDelta;

    private boolean mInvalidGesture;

    // Pointer IDs currently responsible for the two fingers controlling the gesture缩放
    private int mActiveId0;
    private int mActiveId1;
    private boolean mActive0MostRecent;

    ScaleGestureDetector(OnScaleGestureListener listener) {
        mListener = listener;
        mCurrSpanVector = new Vector2D();
    }

    boolean onTouchEvent(Component view, TouchEvent event) {
        MmiPoint point = event.getPointerPosition(event.getIndex());
        final int action = event.getAction();
        if (action == TouchEvent.PRIMARY_POINT_DOWN) {
            reset();// Start fresh
        }

        boolean handled = true;
        if (mInvalidGesture) {
            handled = false;
        } else if (!mGestureInProgress) {
            switch (action) {
                case TouchEvent.PRIMARY_POINT_DOWN: {
                    mActiveId0 = event.getPointerId(0);
                    mActive0MostRecent = true;
                }
                break;

                case TouchEvent.PRIMARY_POINT_UP:
                    reset();
                    break;
                //TODO 鸿蒙没有解决方案
                case TouchEvent.BUILTIN_KEY: {//todo ACTION_POINTER_DOWN 一个非主指针已经下降,来检索改变的指针的索引。
                    // We have a new multi-finger gesture
                    //todo  鸿蒙没有解决方案
                    if (mPrevEvent != null)
                        //todo 在鸿蒙未找到解决方案
//                        mPrevEvent.recycle();
                        //TODO 鸿蒙没有解决方案
//                    mPrevEvent = TouchEvent.obtain(event);
                        mTimeDelta = 0;

                    int index1 = event.getIndex();
                    int index0 = event.getPointerId(mActiveId0);
                    mActiveId1 = event.getPointerId(index1);
                    if (index0 < 0 || index0 == index1) {
                        // Probably someone sending us a broken event stream.
                        index0 = findNewActiveIndex(event, mActiveId1, -1);
                        mActiveId0 = event.getPointerId(index0);
                    }
                    mActive0MostRecent = false;

                    setContext(view, event);

                    mGestureInProgress = mListener.onScaleBegin(view, this);
                    break;
                }
            }
        } else {
            // Transform gesture in progress - attempt to handle it
            switch (action) { //TODO 鸿蒙没有解决方案
                case TouchEvent.BUILTIN_KEY: //todo ACTION_POINTER_DOWN 一个非主指针已经下降,来检索改变的指针的索引。
                {
                    // End the old gesture and begin a new one with the most recent two fingers.
                    mListener.onScaleEnd(view, this);
                    final int oldActive0 = mActiveId0;
                    final int oldActive1 = mActiveId1;
                    reset();
                    //TODO 鸿蒙没有解决方案
//                    mPrevEvent = TouchEvent.obtain(event);
                    mActiveId0 = mActive0MostRecent ? oldActive0 : oldActive1;
                    mActiveId1 = event.getPointerId(event.getIndex());
                    mActive0MostRecent = false;

                    int index0 = event.getPointerId(mActiveId0);
                    if (index0 < 0 || mActiveId0 == mActiveId1) {
                        // Probably someone sending us a broken event stream.
                        index0 = findNewActiveIndex(event, mActiveId1, -1);
                        mActiveId0 = event.getPointerId(index0);
                    }

                    setContext(view, event);

                    mGestureInProgress = mListener.onScaleBegin(view, this);
                }
                break;

                case TouchEvent.OTHER_POINT_UP: {
                    final int pointerCount = event.getPointerCount();
                    final int actionIndex = event.getIndex();
                    event.getIndex();
                    final int actionId = event.getPointerId(actionIndex);

                    boolean gestureEnded = false;
                    if (pointerCount > 2) {
                        if (actionId == mActiveId0) {
                            final int newIndex = findNewActiveIndex(event, mActiveId1, actionIndex);
                            if (newIndex >= 0) {
                                mListener.onScaleEnd(view, this);
                                mActiveId0 = event.getPointerId(newIndex);
                                mActive0MostRecent = true;
                                //TODO 鸿蒙没有解决方案
//                                mPrevEvent = TouchEvent.obtain(event);
                                setContext(view, event);
                                mGestureInProgress = mListener.onScaleBegin(view, this);
                            } else {
                                gestureEnded = true;
                            }
                        } else if (actionId == mActiveId1) {
                            final int newIndex = findNewActiveIndex(event, mActiveId0, actionIndex);
                            if (newIndex >= 0) {
                                mListener.onScaleEnd(view, this);
                                mActiveId1 = event.getPointerId(newIndex);
                                mActive0MostRecent = false;
                                //TODO 鸿蒙没有解决方案
//                                mPrevEvent = TouchEvent.obtain(event);
                                setContext(view, event);
                                mGestureInProgress = mListener.onScaleBegin(view, this);
                            } else {
                                gestureEnded = true;
                            }
                        } //TODO 鸿蒙没有解决方案
//                        mPrevEvent.recycle();
                        //TODO 鸿蒙没有解决方案
//                        mPrevEvent = TouchEvent.obtain(event);
                        setContext(view, event);
                    } else {
                        gestureEnded = true;
                    }

                    if (gestureEnded) {
                        // Gesture ended
                        setContext(view, event);

                        // Set focus point to the remaining finger
                        final int activeId = actionId == mActiveId0 ? mActiveId1 : mActiveId0;
                        final int index = event.getPointerId(activeId);
                        MmiPoint point_xy = event.getPointerPosition(event.getIndex());
                        mFocusX = point_xy.getX();//index
                        mFocusY = point_xy.getY();//index

                        mListener.onScaleEnd(view, this);
                        reset();
                        mActiveId0 = activeId;
                        mActive0MostRecent = true;
                    }
                }
                break;

                case TouchEvent.CANCEL:
                    mListener.onScaleEnd(view, this);
                    reset();
                    break;

                case TouchEvent.PRIMARY_POINT_UP:
                    reset();
                    break;

                case TouchEvent.POINT_MOVE: {
                    setContext(view, event);

                    // Only accept the event if our relative pressure is within
                    // a certain limit - this can help filter shaky data as a
                    // finger is lifted.
                    if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD) {
                        final boolean updatePrevious = mListener.onScale(view, this);

                        if (updatePrevious) {
//                            mPrevEvent.recycle(); //TODO 鸿蒙没有解决方案
//                            mPrevEvent = TouchEvent.obtain(event);
                        }
                    }
                }
                break;
            }
        }

        return handled;
    }

    private int findNewActiveIndex(TouchEvent ev, int otherActiveId, int removedPointerIndex) {
        final int pointerCount = ev.getPointerCount();

        // It's ok if this isn't found and returns -1, it simply won't match.
        final int otherActiveIndex = ev.getPointerId(otherActiveId);

//        // Pick a new id and update tracking state.
        for (int i = 0; i < pointerCount; i++) {
            if (i != removedPointerIndex && i != otherActiveIndex) {
                return i;
            }
        }
        return -1;
    }

    private void setContext(Component view, TouchEvent curr) {
        if (mCurrEvent != null) {
//            mCurrEvent.recycle(); //TODO 鸿蒙没有解决方案
        }
//        mCurrEvent = TouchEvent.obtain(curr); //TODO 鸿蒙没有解决方案

        mCurrLen = -1;
        mPrevLen = -1;
        mScaleFactor = -1;
        //TODO Point 设置点的x和y坐标, 鸿蒙无对应方法
//        mCurrSpanVector.set(0.0f, 0.0f);
        final TouchEvent prev = mPrevEvent;
        final int prevIndex0 = prev.getPointerId(mActiveId0);
        final int prevIndex1 = prev.getPointerId(mActiveId1);
        final int currIndex0 = curr.getPointerId(mActiveId0);
        final int currIndex1 = curr.getPointerId(mActiveId1);

        if (prevIndex0 < 0 || prevIndex1 < 0 || currIndex0 < 0 || currIndex1 < 0) {
            mInvalidGesture = true;
//            Log.e(TAG, "Invalid MotionEvent stream detected.", new Throwable());
            if (mGestureInProgress) {
                mListener.onScaleEnd(view, this);
            }
            return;
        }
        MmiPoint point = prev.getPointerPosition(prev.getIndex());
        final float px0 = point.getX();//TODO prevIndex0
        final float py0 = point.getY();//TODO prevIndex0
        final float px1 = point.getX();//TODO prevIndex1
        final float py1 = point.getY();//TODO prevIndex1
        final float cx0 = point.getX();//TODO currIndex0
        final float cy0 = point.getY();//TODO currIndex0
        final float cx1 = point.getX();//TODO currIndex1
        final float cy1 = point.getY();//TODO currIndex1


        final float pvx = px1 - px0;
        final float pvy = py1 - py0;
        final float cvx = cx1 - cx0;
        final float cvy = cy1 - cy0;
        Point point1 = new Point();
        //TODO Point 设置点的x和y坐标, 鸿蒙无对应方法
//        mCurrSpanVector.set(cvx, cvy);
        mPrevFingerDiffX = pvx;
        mPrevFingerDiffY = pvy;
        mCurrFingerDiffX = cvx;
        mCurrFingerDiffY = cvy;

        mFocusX = cx0 + cvx * 0.5f;
        mFocusY = cy0 + cvy * 0.5f;
        mTimeDelta = curr.getOccurredTime() - prev.getOccurredTime();
//        mCurrPressure = curr.getPressure(currIndex0) + curr.getPressure(currIndex1); //TODO 鸿蒙没有解决方案
//        mPrevPressure = prev.getPressure(prevIndex0) + prev.getPressure(prevIndex1); //TODO 鸿蒙没有解决方案
    }

    private void reset() {
        if (mPrevEvent != null) {
            //TODO 鸿蒙没有此方法
//            mPrevEvent.recycle();
            mPrevEvent = null;
        }
        if (mCurrEvent != null) {
            //TODO 鸿蒙没有此方法
//            mCurrEvent.recycle();
            mCurrEvent = null;
        }
        mGestureInProgress = false;
        mActiveId0 = -1;
        mActiveId1 = -1;
        mInvalidGesture = false;
    }

    boolean isInProgress() {
        return mGestureInProgress;
    }

    float getFocusX() {
        return mFocusX;
    }

    float getFocusY() {
        return mFocusY;
    }

    private float getCurrentSpan() {
        if (mCurrLen == -1) {
            final float cvx = mCurrFingerDiffX;
            final float cvy = mCurrFingerDiffY;
            mCurrLen = (float) Math.sqrt(cvx * cvx + cvy * cvy);
        }
        return mCurrLen;
    }

    Vector2D getCurrentSpanVector() {
        return mCurrSpanVector;
    }

    public float getCurrentSpanX() {
        return mCurrFingerDiffX;
    }

    public float getCurrentSpanY() {
        return mCurrFingerDiffY;
    }

    private float getPreviousSpan() {
        if (mPrevLen == -1) {
            final float pvx = mPrevFingerDiffX;
            final float pvy = mPrevFingerDiffY;
            mPrevLen = (float) Math.sqrt(pvx * pvx + pvy * pvy);
        }
        return mPrevLen;
    }

    public float getPreviousSpanX() {
        return mPrevFingerDiffX;
    }

    public float getPreviousSpanY() {
        return mPrevFingerDiffY;
    }

    public float getScaleFactor() {
        if (mScaleFactor == -1) {
            mScaleFactor = getCurrentSpan() / getPreviousSpan();
        }
        return mScaleFactor;
    }

    public long getTimeDelta() {
        return mTimeDelta;
    }

    public long getEventTime() {
        return mCurrEvent.getStartTime();
    }

}
